/******************************************************************************
 * (C) Copyright 2013 Atech-Automotive
 * FILE NAME:    uds_diag_interface.c
 * DESCRIPTION:
 * 
 * DATE BEGUN:   2015/05/07
 * BY:           hui.pang
 * PRODUCT NAME:
 * APPLICATION:
 * TARGET H/W:
 * DOC REF:
 *****************************************************************************
 */

/*****************************************************************************
** #include 
*****************************************************************************/
#include "system.h"
#include "uds_diag_interface.h"
    
#include "uds_diag_drv.h"

#include "uds_can_trans.h"
#include "uds_diag_appl.h"
#include "uds_diag_fun.h"

#pragma CODE_SEG  OTHER_ROM


/*****************************************************************************
** typedef
*****************************************************************************/


/*
** Structure for vectoring to message handlers.
** mode      = mode byte in message
** function  = pointer to function to call to process the message
*/
typedef struct
{
    Uds_DiagMode_E mode;
    void (*function)(void);
    
} Uds_DiagVector_S;

/*****************************************************************************
** #define
*****************************************************************************/
/* Last Address in the Diag Message Table */
#define  LAST_DIAG_VECTOR_RECORD_ADDRESS (&diag_vectors_rom[(sizeof(diag_vectors_rom)/sizeof(Uds_DiagVector_S)-1u)])

/*  Used for Resp78 Handling  */
#define  TIMEOUT_3_SECONDS       (30)  /* in 100ms*/
#define  TIMEOUT_60_SECONDS      (600) /* in 100ms */

/*****************************************************************************
** global variable
*****************************************************************************/
Uds_DiagSts_E g_uds_diag_status;

UINT8  g_u8_diag_neg_resp78_timer = CLEAR;

UINT16 g_u16_diag_resp78_timeout_timer = CLEAR;

/*****************************************************************************
** static variables
*****************************************************************************/
/*
** Negative Response 78 mode 
*/
static UINT8 s_u8_diag_resp_78_mode = 0x00;

/*
** Single Frame Buffer used to hold resp78 message.
*/
static UINT8 s_u8_diag_78_buff[8];

/*****************************************************************************
** static constants
*****************************************************************************/
/*
** Diagnostic message vector table.
*/ 
static const Uds_DiagVector_S diag_vectors_rom[] =
{  

#ifdef MODE_10_SUPPORTED   /* 0x10 */
    {ENTRDIAG,  UdsAppl_DiagDiagnosticSessionCtrl_0x10}, 
#endif
    
#ifdef MODE_3E_SUPPORTED   /* 0x3E */
    {TSTRPRNT,  UdsAppl_DiagTesterPresent_0x3E}, 
#endif
    
#ifdef MODE_27_SUPPORTED   /* 0x27 */
    {SECACCESS, UdsAppl_DiagSecurityAccess_0x27},
#endif
    
#ifdef MODE_22_SUPPORTED   /* 0x22 */
    {RDBYID,    UdsAppl_DiagReadDataByIdentifier_0x22},
#endif
    
#ifdef MODE_2E_SUPPORTED   /* 0x2E */
    {WRBYID,    UdsAppl_DiagWriteDataByIdentifier_0x2E},
#endif
    
#ifdef MODE_19_SUPPORTED   /* 0x19 */
    {DTCINFO,   UdsAppl_DiagReadDTCInformation_0x19},  
#endif		
    
#ifdef MODE_14_SUPPORTED   /* 0x14 */  
    {CLRDTCRQ,  UdsAppl_DiagClearDiagnosticInformation_0x14},
#endif
    
#ifdef MODE_2F_SUPPORTED   /* 0x2F */ 
    {IOCTRLBYID, UdsAppl_DiagInputOutputCtrlByIdentifier_0x2F},
#endif
    
#ifdef MODE_31_SUPPORTED   /* 0x31 */ 
    {ROUTINECTRL, UdsAppl_DiagRoutineCtrlByIdentifier_0x31},
#endif
    
#ifdef MODE_11_SUPPORTED   /* 0x11 */ 
    {ECURESET, UdsAppl_DiagECUReset_0x11},
#endif

#ifdef MODE_28_SUPPORTED   /* 0x28 */ 
    {COMMCTRL, UdsAppl_DiagCommCtrl_0x28},
#endif

#ifdef MODE_85_SUPPORTED   /* 0x85 */ 
    {DTCSETTINGCTRL, UdsAppl_DiagDTCSettingCtrl_0x85},
#endif

#ifdef MODE_23_SUPPORTED   /* 0x23 */ 
    {RDMBYADDR, UdsAppl_DiagReadMemoryByAddress_0x23},
#endif

#ifdef MODE_3D_SUPPORTED   /* 0x3D */ 
    {WRMBYADDR, UdsAppl_DiagWriteMemoryByAddress_0x3D}
#endif

};

/*****************************************************************************
** static function prototypes
*****************************************************************************/
static void UdsInterface_VoltageStateHandler( void );
static void UdsInterface_NodeHandler( void );
static void DiagNegativeResponse78Handler( void );
static void UdsInterface_Send78Response( void );

/*****************************************************************************
** function prototypes
*****************************************************************************/


/****************************************************************************/
/****************************************************************************/
/**
 * Function Name: UdsInterface_Init
 * Description: This function initialises flags and variables.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
void UdsInterface_Init( void )
{
    /* clear all diagnostics status flags */
    CLEARBIT(g_uds_diag_status, (PROCESSING_MSG | COMMANDRCVD | NEGRESP78_PROCESSING | NEGRESP78_WAIT_60SEC));
    s_u8_diag_resp_78_mode = 0;
    (void)memset(s_u8_diag_78_buff, 0, sizeof(s_u8_diag_78_buff));
}

/****************************************************************************/
/**
 * Function Name: UdsInterface_ReleaseRxBuff
 * Description: This function releases diagnostics RX buffer to the "available"
 *              state so it can be used to receive the next incoming diagnostic
 *              message.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
void UdsInterface_ReleaseRxBuff( void )
{
    /*
    ** Two actions are necessary to release the RX buffer and make it available:
    ** clear PROCESSING_MSG bit and set message length in RX message length to 0.
    */
    CLEARBIT(g_uds_diag_status, PROCESSING_MSG);
    CLEARBIT(g_uds_diag_status, COMMANDRCVD);
    /* 
    ** g_cantp_rx_buffer.info_byte is cleared.
    */
    g_cantp_rx_buffer.info_byte = 0;
}

/****************************************************************************/
/**
 * Function Name: UdsInterface_ClearResp78Flag
 * Description: This function clear NEGRESP78_PROCESSING flag.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
void UdsInterface_ClearResp78Flag( void )
{
    CLEARBIT(g_uds_diag_status, NEGRESP78_PROCESSING);   
}

/****************************************************************************/
/**
 * Function Name: UdsInterface_Handler10ms
 * Description: This function is a primary diagnostic control function. This
 *		   	    function is called periodically by the UdsAppl_Handler10ms function.
 *              This function checks for new diagnostic message.If any new diag
 *              message comes it will call corresponding Appl layer function.
 *              It also handles Negative Response $78 handling.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
void UdsInterface_Handler10ms( void )
{
    const Uds_DiagVector_S *table;

    if(c_b_diag_stop_low_or_high_vbat)
    {
        UdsInterface_VoltageStateHandler();
    }
    else
    {
        g_cantp_rx_enable = TRUE;
    }

    ////////////////////////////////////////
    
    /*
    ** Run the scheduled portion of the CAN TP layer function.
    */
    CanTrans_Manage();    
    
    /* Check for diagnostic message */
    UdsInterface_NodeHandler();

    if( TESTBIT(g_uds_diag_status, KEEPING_DIAG) != 0 )
    {
        /* Restart Diag Session timer and Dialog timer */
        UdsAppl_DiagResetDiagTimer();
        CLEARBIT(g_uds_diag_status, KEEPING_DIAG);
    }

    /* Check for arrival of new diagnostic command. */
    if( TESTBIT(g_uds_diag_status, COMMANDRCVD) != 0 )
    {
        /* Restart Diag Session timer and Dialog timer */
        UdsAppl_DiagResetDiagTimer();
		
        /* Check for Resp78 handling is not going on  */
        if( TESTBIT(g_uds_diag_status, NEGRESP78_PROCESSING) == 0 )
        {     
            /* Check for TPCI format is correct in the RCVD diag message */
            if(TESTBIT(g_cantp_rx_buffer.info_byte,RX_MSG_INVL_TPCI)==0)
            {    
                /* Check for Transfer Aborted condition */
                if(TESTBIT(g_cantp_rx_buffer.info_byte,TX_ABORTED)==0)
                {
                    /* Point to beginning of lookup table */
                    table =  &diag_vectors_rom[0];         
                    /* Traverse table to find the command received. */
                    while (table <= LAST_DIAG_VECTOR_RECORD_ADDRESS)
                    {
                        /* Check for mode match */
                        if (g_cantp_rx_buffer.msg[ __MODE ] == table->mode)
                        {
                            if(DiagDataLength !=0)
                            { 
                                DiagDataLength = g_cantp_rx_buffer.msg_length;
                            }
                            
                            /* 
                            ** Call corresponding Appln layer function 
                            ** process the diag command.
                            */
                            table->function();
                            break;              
                        }
                        table++;
                    }

                    /* Check if the mode was not found in the lookup table */
                    if (table > LAST_DIAG_VECTOR_RECORD_ADDRESS)
                    {
                        /* quit without send any negative response */
				        UdsInterface_QuitWithoutSendNegativeResponse();	 
				        if( g_diag_can_address_mode == DIAG_PHYSIC_ADDR_MODE )
        				{
        				    /* 0x11 - should response when get the wrong message 
        				              in physical mode */
        					DiagExServiceNotSupported_Nrc11();
        				}				
                    }
                }
                else /* if(TESTBIT(g_cantp_rx_buffer.info_byte,TX_ABORTED)==0) */
                {
                    /*
                    ** This response code indicates that a data transfer operation
                    ** was halted due to a fault.The active transferData sequence
                    ** shall be aborted.
                    */		
                    /* quit without send any negative response */
                    UdsInterface_QuitWithoutSendNegativeResponse();	 
                }        
            }
            else /* if(TESTBIT(g_cantp_rx_buffer.info_byte,RX_MSG_INVL_TPCI)==0) */
            {
                /* quit without send any negative response */
		        UdsInterface_QuitWithoutSendNegativeResponse();	 
            }
        }
        else /* if(TESTBIT(g_uds_diag_status, NEGRESP78_PROCESSING) == 0) */
        {
            /* Diag Message is rcvd during $78 resp handling */
            /* Release RX buffer to allow receive next message */
            UdsInterface_ReleaseRxBuff();
            /* Clear timer to send negative resp$78 immediately for this diag req */
            g_u8_diag_neg_resp78_timer  = 0x00;
        }           

        /* Clear command received flag */   
        CLEARBIT(g_uds_diag_status, COMMANDRCVD);
    }
    
    /* 
    ** Call Resp78 Handler to send response $78 if any req message requires more
    ** than 50ms to response with postive or negative response(except $78).
    ** Resp $78 is send by this handler for every 4 seconds.
    */
    DiagNegativeResponse78Handler();   	
}


/****************************************************************************/
/**
 * Function Name: UdsInterface_VoltageStateHandler
 * Description: none
 *
 * Param:   none
 * Return:  none
 * Author:  2017/01/17, hui.liu create this function
 ****************************************************************************/
static void UdsInterface_VoltageStateHandler( void )
{
    static enum
    {
        DIAG_VBAT_LOW,
        DIAG_VBAT_NORMAL,
        DIAG_VBAT_HIGH,
    }e_diagVbatSts = DIAG_VBAT_NORMAL;
    
    static UINT16 u16_highVbatCounter = 0;
    static UINT16 u16_lowVbatCounter = 0;
    
    UINT8 u8_diagVbat;
    
    u8_diagVbat = UdsDiag_GetVbatVoltage();
    
    switch( e_diagVbatSts )
    {
        case DIAG_VBAT_HIGH:
            
            g_cantp_rx_enable = FALSE;
            
            if( u8_diagVbat < c_u8_diag_high_vbat_th )
            {
                if(++u16_highVbatCounter > c_u16_diag_high_vbat_recover_time)
                {
                    e_diagVbatSts = DIAG_VBAT_NORMAL;
                    u16_highVbatCounter = 0;
                }
            }
            else
            {
                u16_highVbatCounter = 0;
            }
            break;

        case DIAG_VBAT_NORMAL :
            
            g_cantp_rx_enable = TRUE;
            
            if( u8_diagVbat < c_u8_diag_low_vbat_th )
            {
                if(++u16_lowVbatCounter > c_u16_diag_low_vbat_off_time)
                {
                    u16_lowVbatCounter = 0;
                    e_diagVbatSts = DIAG_VBAT_LOW;
                }
            }
            else
            {
                u16_lowVbatCounter = 0;
            }
            
            if( u8_diagVbat > c_u8_diag_high_vbat_th )
            {
                if(++u16_highVbatCounter > c_u16_diag_high_vbat_off_time)
                {
                    u16_highVbatCounter = 0;
                    e_diagVbatSts = DIAG_VBAT_HIGH;
                }
            }
            else
            {
                u16_highVbatCounter = 0;
            }
            break;
        
        case DIAG_VBAT_LOW:
            
            g_cantp_rx_enable = FALSE;
            
            if( u8_diagVbat > c_u8_diag_low_vbat_th )
            {
                if(++u16_lowVbatCounter > c_u16_diag_low_vbat_recover_time)
                {
                    u16_lowVbatCounter = 0;
                    e_diagVbatSts = DIAG_VBAT_NORMAL;
                }
            }
            else
            {
                u16_lowVbatCounter = 0;
            }
            break;

        default:
            e_diagVbatSts = DIAG_VBAT_LOW;
            break;
    }
}

/****************************************************************************/
/**
 * Function Name: UdsInterface_NodeHandler
 * Description: This function checks to see if a new message (command)
 *              has been received and needs to be processed.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
static void UdsInterface_NodeHandler( void )
{
    /* 
    ** Check to see if a new message has arrived. New message
    ** arrival is indicated when PROCESSING_MSG bit is clear.
    */
    if( TESTBIT(g_uds_diag_status, PROCESSING_MSG) == 0 )
    {
        if( TESTBIT(g_cantp_rx_buffer.info_byte, RX_MSG_RCVD) != 0 )
        {
            SETBIT(g_uds_diag_status, COMMANDRCVD);
            SETBIT(g_uds_diag_status, PROCESSING_MSG);
        }
    }
    else
    {
        /*
        ** When processing a message, the RX buffer length should always be
        ** non-zero. If not, the PROCESSING_MESSAGE bit must be cleared so
        ** incoming messages can be processed! 
        */
        if (TESTBIT(g_cantp_rx_buffer.info_byte,RX_MSG_RCVD) == 0)
        {
            CLEARBIT(g_uds_diag_status, PROCESSING_MSG);
        }
    }        
}

/****************************************************************************/
/**
 * Function Name: UdsInterface_PutResponse
 * Description: This function will send positive response to the tester.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
void UdsInterface_PutResponse( BOOL b_forbid_flag, UINT16 msg_length )
{
    Uds_TxDesc_S  tx_desc;
    

    
    /*
    ** Positive response is given to the tester.Incoming msg processing 
    ** is complete.So clear NEGRESP78_PROCESSING flag to not send resp$78
    ** again.
    */
    CLEARBIT(g_uds_diag_status, NEGRESP78_PROCESSING);
    
    /*
    ** Release the receive buffer so that it is available
    ** for the next incoming message.  
    */
    UdsInterface_ReleaseRxBuff();

    if( FALSE == b_forbid_flag ) /* we only send response msg when length is not 0XFF, 
                                    when lenght is 0xff, it means we do not need to 
                                    response */
    {
	    g_cantp_rx_buffer.msg[__MODE] += (UINT8)0x40;

	    if( 0x00 == msg_length )
	    {
	        tx_desc.msg_length = g_cantp_rx_buffer.msg_length; 
            tx_desc.length1    = g_cantp_rx_buffer.msg_length;
        }
        else
        {
            tx_desc.msg_length = msg_length;
            tx_desc.length1    = msg_length;
        }
	    tx_desc.ptr1       = &g_cantp_rx_buffer.msg[__MODE];
	    

	    (void)CanTrans_TxMsg(&tx_desc);
    }
}

/****************************************************************************/
/**
 * Function Name: UdsInterface_SendNegativeResponse
 * Description: This function a negative response message to the tester.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/07, hui.pang create this function
 ****************************************************************************/
void UdsInterface_SendNegativeResponse(UINT8 response)
{   
    Uds_TxDesc_S  tx_desc;

    /*
    ** Positive response is given to the tester.Incoming msg processing 
    ** is complete.So clear NEGRESP78_PROCESSING flag to not send resp$78
    ** again.
    */
    CLEARBIT(g_uds_diag_status,NEGRESP78_PROCESSING);
    
    /*
    ** Release the receive buffer so that it is available
    ** for the next incoming message.  
    */
    UdsInterface_ReleaseRxBuff();
    g_cantp_rx_buffer.msg[ _DATA1 ] = g_cantp_rx_buffer.msg[ __MODE  ];  
    g_cantp_rx_buffer.msg[ __MODE  ] = (UINT8)0x7F;
    g_cantp_rx_buffer.msg[ _DATA2 ] = response;
    g_cantp_rx_buffer.msg_length = 3;
    
    tx_desc.msg_length = g_cantp_rx_buffer.msg_length; 
    tx_desc.ptr1       = &g_cantp_rx_buffer.msg[ __MODE ];
    tx_desc.length1    = g_cantp_rx_buffer.msg_length;

    (void)CanTrans_TxMsg(&tx_desc);    
    
}   

/****************************************************************************/
/**
 * Function Name: UdsInterface_QuitWithoutSendNegativeResponse
 * Description: This function a negative response message to the tester.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
void UdsInterface_QuitWithoutSendNegativeResponse( void )
{   
    /*
    ** Positive response is given to the tester.Incoming msg processing 
    ** is complete.So clear NEGRESP78_PROCESSING flag to not send resp$78
    ** again.
    */
    CLEARBIT(g_uds_diag_status,NEGRESP78_PROCESSING);
    
    /*
    ** Release the receive buffer so that it is available
    ** for the next incoming message.  
    */
    UdsInterface_ReleaseRxBuff();
}    

/****************************************************************************/
/**
 * Function Name: DiagNegativeResponse78Handler
 * Description: This function manages resp $78 handling if any request
 *              message requires more than 50ms to process.  
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/07, hui.pang create this function
 ****************************************************************************/
static void DiagNegativeResponse78Handler( void )
{
    /*
    ** If PROCESSING_MSG bit is set, this function has to send Resp message $78
    ** for every <=4 seconds interval.Set NEGRESP78_PROCESSING flag,Send Message $78
    ** and start the 3 second SW timer.
    */
    if( TESTBIT(g_uds_diag_status, PROCESSING_MSG) != 0 )
	{
        s_u8_diag_resp_78_mode = g_cantp_rx_buffer.msg[__MODE];
        SETBIT(g_uds_diag_status,(NEGRESP78_PROCESSING | NEGRESP78_WAIT_60SEC));

        g_u8_diag_neg_resp78_timer      = TIMEOUT_3_SECONDS; /* we actually not using this time out */
        g_u16_diag_resp78_timeout_timer = TIMEOUT_60_SECONDS; /* wait 3s intead of 60s, TIMEOUT_60_SECONDS */

        UdsInterface_Send78Response();
	}
    else
	{
        /*
        ** If NEGRESP78_PROCESSING bit set and timer expires, Send Neg Resp $78.
        */
        if(TESTBIT(g_uds_diag_status,NEGRESP78_PROCESSING) != 0)
	    {
            if( 0x00 == g_u8_diag_neg_resp78_timer )
            {
                g_u8_diag_neg_resp78_timer = TIMEOUT_3_SECONDS;
                UdsInterface_Send78Response();
            }
    
            if( 0x00 == g_u16_diag_resp78_timeout_timer )
	        {
	            CLEARBIT(g_uds_diag_status, NEGRESP78_WAIT_60SEC);
	        }
        }
	}
}

/****************************************************************************/
/**
 * Function Name: UdsInterface_Send78Response
 * Description: This function will send negative response message with response
 *              code $78.
 *
 * Param:   none
 * Return:  none
 * Author:  2015/05/06, hui.pang create this function
 ****************************************************************************/
static void UdsInterface_Send78Response( void )
{
    Uds_TxDesc_S  tx_desc;

    /////////////////////////////////////
    
    /*
    ** Release the receive buffer so that it is available
    ** for the next incoming message.  
    */
    UdsInterface_ReleaseRxBuff();

    /////////////////////////////////////////////
    
    s_u8_diag_78_buff[__MODE] = 0x7F;
    s_u8_diag_78_buff[_DATA1] = s_u8_diag_resp_78_mode;
    s_u8_diag_78_buff[_DATA2] = 0x78;    
        
    tx_desc.msg_length = 3;
    tx_desc.ptr1       = &s_u8_diag_78_buff[__MODE];
    tx_desc.length1    = 3;

    (void)CanTrans_TxMsg(&tx_desc);
}

#pragma CODE_SEG  DEFAULT


/*****************************************************************************
** End File
*****************************************************************************/
